#ifndef IMAGE_H_INCLUDED
#define IMAGE_H_INCLUDED
#include "types.h"
#include <list>
#include <queue>
#include <stack>
#include <string>

#define SIZE_NOT_DEFINED 0.0f

class Color_Image;
class Binary_Image;
class Grey_Image;

#ifndef NULL
#define NULL 0
#endif

using namespace std;

/** \file image.h
*   \brief Define image objects
*/


/** \class Image.
*   \brief An image super class.
*   This is a base class for all image class in this application.
*/

class Image{
   public:
        enum ImageType{
            BINARY,
            GREY,
            COLOR,
            DATA};

   private:
        ///Pixel size in the real world.
        ///In meters
        float pixelsize;
        ///A Name for the image.
        string name;
        ///image Height.
        unsigned int height;
        ///image Width.
        unsigned int width;

        ///Identify image type
        ImageType type;
    protected:
        ///Identify image type/ called by constructor
        void setType(ImageType type);
        ///Set Height
        void setHeight(unsigned int h);
        ///Set Width
        void setWidth(unsigned int w);
    public:

        ///Set the pixel size in the real world.
        void setPixelSize(float meters);
        ///Get the pixel size in the real world.
        float getPixelSize() const;

        ///Get the image Height
        unsigned int getHeight() const;

        ///Get the image Width
        unsigned int getWidth() const;

        ///Get the image type
        ImageType getType();

        ///Invert the values of the image pixels
        virtual void invert();

        ///Save image in a file
        ///\param filename filename with path
        ///\param type type of file. Default="png", others: "ico","jpeg","bmp"
        //void saveToFile(string filename,string type = "png");

        ///Convert a image to other type
        ///\param newtype New type, if new type = old type, copy image;
        ///\param option Option for conversion
        ///\param value Some options needs some param
        /**Options:
        Bynary_Image to Grey_image :
        option=0 -> Grey_Image takes 1 for object(true)
        option=1 -> Grey_Image takes white(255) for object(true)
        Bynary_Image to Color_image :
        option=0 -> Color_Image takes white(255,255,255) for object(true)
        Grey_image to Bynary_Image::
        option=0 -> Binary_Image takes true for Grey_Image value = value in param
        option=1 -> Binary_Image takes true for Grey_Image value >= value in param
        option=2 -> Binary_Image takes true for Grey_Image value <= value in param
        Grey_image to Color_Image:
        option=0 -> Color_image keeps grey scale
        option=1 -> Colorize image, each value takes random color
        Color_image to Binary_Image:
        option=0 -> Binary_Image takes true for Color_Image value != Black(0,0,0)
        option=1 -> Binary_Image takes true for Color_Image red value != 0 (0,?,?)
        option=2 -> Binary_Image takes true for Color_Image green value != 0 (?,0,?)
        option=3 -> Binary_Image takes true for Color_Image blue value != 0 (?,?,0)
        Color_image to Grey_Image:
        option=0 -> Grey_Image takes mean value of channels
        option=1 -> Grey_Image takes red value
        option=2 -> Grey_Image takes green value
        option=3 -> Grey_Image takes blue value
        */
        virtual Image* convert(ImageType newtype,int option=0,unsigned int value=1)=0;

        Image* copy(Image* imageout=NULL);

        virtual ~Image();

        //static Color_Image* openFromFile(string path);

};

typedef Image::ImageType ImageType;

class ColorPixel{
    public:
        unsigned char red;
        unsigned char green;
        unsigned char blue;

        ColorPixel(unsigned char red=0,unsigned char green=0,unsigned char blue=0);
        ~ColorPixel();

        unsigned char getRed();
        unsigned char getGreen();
        unsigned char getBlue();

        bool operator==(ColorPixel a);

        bool operator!=(ColorPixel a);

        void setRed(unsigned char value);
        void setGreen(unsigned char value);
        void getBlue(unsigned char value);

};

class Color_Image : public Image{
    public:
        ColorPixel **pixelmap;

        ///Constructor
        ///Initialize/Allocate pixmap.
        /// \param height image height
        /// \param width image width
        Color_Image(unsigned int height,unsigned int width);

         ///Destructor.
        ///Desallocate pixmap.
        ~Color_Image();

        ///Set one pixel of image.
        ///\param position The Position that will be seted.
        ///\param value Pixel seted.
        void setPixel(Position position,ColorPixel value);

        ///Get a pixel from a Position
        ///\param position Position of pixel which will be got.
        ColorPixel getPixel(Position position);

        ///Get a pixel from a Position
        ///\param xposition position in x of pixel which will be got.
        ///\param yposition position in y of pixel which will be got.
        ColorPixel getPixel(int xposition,int yposition);

        ///Invert image, Logical/Binary operation
        void invert();

        Image* convert(ImageType newtype,int option=0,unsigned int value=1);

        ///Generate one copy of image in param
        ///\param imageout receive copy
        ///\return image copy
        Color_Image* colorcopy(Color_Image* imageout=NULL);

};

/** \class Binary_Image
*   \brief Class of binary images
*/

class Binary_Image : public Image{
    public:
        ///Matrix: Map of Pixels.
        bool **pixelmap;

        ///Constructor
        ///Initializes/Allocates a pixel map.
        ///Important: The pixel map should be created with 2 exceeding rows and lines, in order to perform its contour extraction afterwards
        /// \param height image height
        /// \param width image width
        Binary_Image(unsigned int height,unsigned int width);


        ///Destructor.
        ///Desllocates memory space for the pixel map.
        ~Binary_Image();

        ///Assigns a value to a pixel of the image.
        ///\param position The Position to where the value will be assigned.
        ///\param value Value assigned.
        void setPixel(Position position,bool value);

        ///Assigns a value to a pixel of the image.
        ///\param xposition The x coordinate of the Position to where the value will be assigned.
        ///\param yposition The y coordinate of the Position to where the value will be assigned.
        ///\param value Value assigned.
        void setPixel(int xposition,int yposition,bool value);

        ///Get a pixel value from a Position
        ///\param position Position of the pixel whose value shall be retrieved.
        bool getPixel(Position position);

        ///Get a pixel value from a Position
        ///\param xposition The x coordinate of the Position whose value shall be retrieved.
        ///\param yposition The y coordinate of the Position whose value shall be retrieved.
        bool getPixel(int xposition,int yposition);

        ///Invert image, Logical/Binary operation
        void invert();

        Image* convert(ImageType newtype,int option=0,unsigned int value=1);

        ///Logical AND operation with other image
        ///Set intersection
        void AND(Binary_Image *img);

        ///Logical OR operation with other image
        ///Set union
        void OR(Binary_Image *img);

        ///Set Difference
        void DIFFERENCE(Binary_Image *img);

        void drawCircle(int centerx,int centery,unsigned int radii);


        ///Returns a pointer to a list of pixels present in the image with a specific label.
        ///The pixels order is according to a raster scanning from upper left to the bottom right image corner
        ///\param Label default=true.
        list<Position>* getListofPoints(bool type=true);

        ///Returns a pointer to a queue of pixels present in the image with a specific label.
        ///The pixels order is according to a raster scanning from upper left to the bottom right image corner
        ///\param Label default=true.
        queue<Position>* getQueueofPoints(bool type=true);

        ///Gets one stack of points with determined label. . Rasterization begins in upper-left corner and go to the right
        ///\param Label default=true.
        stack<Position>* getStackofPoints(bool type=true);

        ///Generates one copy of image in param
        ///\param imageout receive copy
        ///\return image copy
        Binary_Image* binarycopy(Binary_Image* imageout=NULL);

        ///Compare Images
        ///\param a Image that will be compared
        ///\return If are diferents return false else return true
        bool operator==(Binary_Image* img);

        bool operator!=(Binary_Image* img);



};


/** \class Grey_Image
*   \brief Class of images in grey scale
*/
class Grey_Image : public Image {
    private:
        ///levels in grey scale.
        unsigned int levels;
    public:
        ///Matrix: Map of Pixels.
        unsigned int** pixelmap;

        ///Constructor
        ///Initialize/Allocate pixmap.
        ///Observation:Please create with 2 mores rows and lines if 'is'/'or you will make' a contour extraction
        /// \param height image height
        /// \param width image width
        /// \param levels Levels of greys in grey scale
        Grey_Image(int height,int width,unsigned int levels);


        ///Destructor.
        ///Desallocate pixmap.
        ~Grey_Image();

        ///Set one pixel of image.
        ///\param position The Position that will be seted.
        ///\param value Value seted.
        void setPixel(Position position,unsigned int value);

        ///Set one pixel of image.
        ///\param xposition The position in x that will be seted.
        ///\param yposition The position in y that will be seted.
        ///\param value Value seted.
        void setPixel(int xposition,int yposition,unsigned int value);

        ///Get a pixel from a Position
        ///\param position Position of pixel which will be got.
        unsigned int getPixel(Position position);

        ///Get a pixel from a Position
        ///\param xposition position in x of pixel which will be got.
        ///\param yposition position in y of pixel which will be got.
        unsigned int getPixel(int xposition,int yposition);

        ///Set Height
        void setGreyLevels(unsigned int l);
        ///Get image height
        unsigned int getGreyLevels() const;

        void invert();

        Image* convert(ImageType newtype,int option=0,unsigned int value=1);

        ///Logical AND with other image
        ///Set intersection
        void AND(Binary_Image *img);

        ///Subtract values from other image.
        void MINUS(Grey_Image *img);

        ///add values from other image.
        void ADD(Grey_Image *img);

         ///Get one list of points with determined label. Rasterization begins in upper-left corner and go to the right
        ///\param Label default=1.
        list<Position>* getListofPoints(unsigned int label=1);

        ///Get one queue of points with determined label. Rasterization begins in upper-left corner and go to the right
        ///\param Label default=1.
        queue<Position>* getQueueofPoints(unsigned int label=1);

         ///Get one stack of points with determined label. Rasterization begins in upper-left corner and go to the right
        ///\param Label default=1.
        stack<Position>* getStackofPoints(unsigned int label=1);

        ///Generate one copy of image in param
        ///\param imageout receive copy
        ///\return image copy
        Grey_Image* greycopy(Grey_Image* imageout=NULL);

        static Position getMaximum(Grey_Image *img);

};




#endif // IMAGE_H_INCLUDED
